var util =
{
	letters: "abcdefghijklmnopqrstuvwxyz",
	wordWrap: function(str, width)
	{
		var regex = '.{1,' + width + '}(\\s|$)|.{' + width + '}|.+$';
		return str.match(RegExp(regex, 'g'));
	},
	leftPad: function(str, width)
	{
		var i, temp = [];
		if(typeof(str) !== "string")
			str = str.toString();
		if(str.length >= width)
			return str.substr(0, width);
		for(i = 0; i < width - str.length; ++i)
			temp.push(" ");
		temp.push(str);
		return temp.join("");
	},
	padOrTruncate: function(str, width)
	{
		if(str.length == width)
			return str;
		else if(str.length > width)
			return str.substring(0, width - 3) + "...";
		while(str.length < width)
		{
			str += " ";
		}
		return str;
	},
	floatDigits: function(f, digits)
	{
		if(digits == 0)
			return parseInt(f);
		var factor = Math.pow(10, digits);
		var ret = (parseInt(f * factor) / factor).toString();
		if(ret.indexOf(".") < 0)
		{
			ret = ret + ".";
		}
		while(ret.length - (ret.indexOf(".") + 1) < digits)
			ret = ret + "0";
		return ret;
	},
	bytesToKb: function(bytes)
	{
		return Math.floor((bytes / 1024) * 10) / 10;
	},
	_colorCountRegExp: new RegExp("\%[^\%]{2}", "igm"),
	_colorEscapeCountRegExp: new RegExp("\%\%", "igm"),
	_codeCountRegExp: new RegExp("\#[^\#]{2}", "igm"),
	_codeEscapeCountRegExp: new RegExp("\#\#", "igm"),
	getFormattedStringLength: function(str) {
		var colorCount = str.match(this._colorCountRegExp);
		colorCount = colorCount == null ? 0 : colorCount.length;

		var colorEscapeCount = str.match(this._colorEscapeCountRegExp);
		colorEscapeCount = colorEscapeCount == null ? 0 : colorEscapeCount.length;

		var codeCount = str.match(this._codeCountRegExp);
		codeCount = codeCount == null ? 0 : codeCount.length;

		var codeEscapeCount = str.match(this._codeEscapeCountRegExp);
		codeEscapeCount = codeEscapeCount == null ? 0 : codeEscapeCount.length;

		var length = str.length;
		length -= colorCount * 3;
		length -= colorEscapeCount;
		length -= codeCount * 3;
		length -= codeEscapeCount;
		return length;
	},
	mix: function(obj, bag) {
		for(var o in bag)
		{
			if(!bag.hasOwnProperty(o))
				continue;
			if(bag.hasOwnProperty(o))
				obj[o] = rand.nextElement(bag[o]);
		}
	},
	addMix: function(dest, src) {
		for(var o in src)
		{
			if(!src.hasOwnProperty(o))
				continue;
			if(!dest.hasOwnProperty(o))
				dest[o] = 0;
			dest[o] += src[o];
		}
		return dest;
	},
	isInArray: function(r, a)
	{
		for(var i = 0; i < a.length; ++i)
		{
			if(r === a[i])
				return true;
		}
		return false;
	},
	floor: function(n, min) { return n < min ? min : n; }
};

// Extension methods
if(!Array.indexOf)
{
	Array.prototype.indexOf = function(obj)
	{
		for(var i = 0; i < this.length; ++i)
		{
			if(this[i] == obj)
				return i;
		}
		return -1;
	}
}

/** Repeatable Random Number Generator.
@param seed The initial seed value (optional).
*/
function Rrng(seed)
{
	if(seed !== undefined)
		this._last = seed;
	else
		this._last = 59051;
}
Rrng.prototype =
{
	/** Gets the next random number in the sequence.
	@param p1 Inclusive minimum (optional).
	@param p2 Exclusive maximum (optional).
	*/
	next: function(p1, p2)
	{
		this._last = (251 * this._last + 32749) % 65521;
		if(p1 != undefined)
		{
			if(p2 != undefined)
				if(p2 == p1)
					return p1;
				else
					return (this._last % (p2 - p1)) + p1;
			else
				return this._last % p1;
		}
		return this._last;
	},
	/** Gets the next float in the sequence in the range 0 to 1 inclusive.
	
	The next float is calculated by getting the next integer from 0 to 10000
	and dividing that by 10000.
	*/
	nextFloat: function()
	{
		return this.next(0, 10001) / 10000;
	},
	/** Gets a random element from an array.
	 *
	 *The array element is calculated by getting the integer from 0 to
	 *array.length and indexing the array by this value. If the object passed
	 *in is not an array the object is returned.
	 */
	nextElement: function(array)
	{
		if(array instanceof Array)
			return array[this.next(0, array.length)];
		return array;
	},
	/** Shorthand for a d20 roll.
	 */
	d20: function()
	{
		return this.next(1, 21);
	},
	/** Shorthand for a d100 roll.
	 */
	d100: function()
	{
		return this.next(1, 100);
	},
	/** Sets the seed.
	@param seed The new seed value.
	*/
	seed: function(seed)
	{
		this._last = seed;
	}
}

/** Global Rrng object which MUST NOT BE USED for generation as it will change
 *on every load.
 */
var rand = new Rrng(Math.floor(Math.random() * 65521));
